package com.planw.beetl.utils;

import com.google.common.base.Optional;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.util.PsiMethodUtil;
import com.intellij.psi.util.PsiTreeUtil;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder;

import java.util.*;

/**
 * @author blin
 */
public final class JavaUtils {

    private JavaUtils() {
        throw new UnsupportedOperationException();
    }


    public static List<PsiClass> findMapperClass(String name, Project project) {
        List<PsiClass> classList = new LinkedList<>();
        loadMapper(classList, name + "Dao", project);
        loadMapper(classList, name + "Mapper", project);
        return classList;
    }

    public static void loadMapper(List<PsiClass> classList, String name, Project project) {
        PsiClass[] psiClasses = JavaUtils.findClazzs(project, name);
        for (PsiClass psiClass : psiClasses) {
            if (psiClass.getSuperClass() == null) {
                continue;
            }
            PsiClass[] interFaces = psiClass.getInterfaces();
            for (PsiClass interFace : interFaces) {
                if (interFace.getQualifiedName().equalsIgnoreCase("org.beetl.sql.mapper.BaseMapper")) {
                    classList.add(psiClass);
                }
            }
        }
    }

    /**
     * 根据名称查询索引的class
     * @param project
     * @param name
     * @return
     */
    @NotNull
    public static PsiClass[] findClazzs(@NotNull Project project, @NotNull String name) {
        GlobalSearchScope scope =  GlobalSearchScope.allScope(project);
        PsiClass[] psiClasses = PsiShortNamesCache.getInstance(project).getClassesByName(name,scope);
        List<PsiClass> classes = Arrays.asList(psiClasses);
        JavaElementFinder finder = JavaElementFinder.Companion.getInstance(project);
        PsiClass[] classes1 = finder.findClasses(name, scope);
        classes.addAll( Arrays.asList(classes1));
        return classes.toArray(new PsiClass[0]);
    }

    @NotNull
    public static PsiField[] findSettablePsiFields(final @NotNull PsiClass clazz) {
        final PsiField[] fields = clazz.getAllFields();
        final List<com.intellij.psi.PsiField> settableFields = new ArrayList<>(fields.length);

        for (final PsiField f : fields) {
            final PsiModifierList modifiers = f.getModifierList();

            if (modifiers != null && (
                    modifiers.hasModifierProperty(PsiModifier.STATIC) ||
                            modifiers.hasModifierProperty(PsiModifier.FINAL))) {
                continue;
            }

            settableFields.add(f);
        }

        return settableFields.toArray(new PsiField[0]);
    }

    public static boolean isElementWithinInterface(@Nullable PsiElement element) {
        if (element instanceof PsiClass && ((PsiClass) element).isInterface()) {
            return true;
        }
        PsiClass type = PsiTreeUtil.getParentOfType(element, PsiClass.class);
        return Optional.fromNullable(type).isPresent() && type.isInterface();
    }

    @NotNull
    public static Optional<PsiClass> findClazz(@NotNull Project project, @NotNull String clazzName) {
        return Optional.fromNullable(JavaPsiFacade.getInstance(project).findClass(clazzName, GlobalSearchScope.allScope(project)));
    }

    @NotNull
    public static Optional<PsiMethod> findMethod(@NotNull Project project, @Nullable String clazzName, @Nullable String methodName) {
        if (StringUtils.isBlank(clazzName) && StringUtils.isBlank(methodName)) {
            return Optional.absent();
        }

        Optional<PsiClass> clazz = findClazz(project, clazzName);
        if (clazz.isPresent()) {
            PsiMethod[] methods = clazz.get().findMethodsByName(methodName, true);
            return ArrayUtils.isEmpty(methods) ? Optional.<PsiMethod>absent() : Optional.of(methods[0]);
        }
        return Optional.absent();
    }

    public static  List<PsiMethod> loadMapperPsiMethod(List<PsiClass> classMapperList,String method) {
        List<PsiMethod> nameMethodsList = new ArrayList<>();
        for (PsiClass psiClass : classMapperList) {
            PsiMethod[] ms = psiClass.getMethods();
            for (PsiMethod m : ms) {
                if (m.getName().equals(method)) {
                    nameMethodsList.add(m);
                }

            }

        }
        return nameMethodsList;
    }

}
